import jsx from '@babel/plugin-syntax-jsx';
import { template, types as t } from '@babel/core';
import { addNamed } from '@babel/helper-module-imports';
// https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts

// const get = (pass, name) => pass.get(`@babel/plugin-react-jsx/${name}`);
// const set = (pass, name, v) => pass.set(`@babel/plugin-react-jsx/${name}`, v);

export default function ({ types: t }) {
  // 插件返回一个对象
  return {
    // 插件名称
    name: 'babel-plugin-transform-react-jsx',
    // babel内部默认是不支持 jsx 的 内部调用了 @babel/plugin-syntax-jsx 插件
    // 继承 转换 jsx 的插件
    inherits: jsx.default,
    // 每个插件都要有一个 visitor
    visitor: {
      // 1. 判断是否有引入 没有就加入一个
      // import { jsx as _jsx } from "react/jsx-runtime"
      Program(path, state) {
        // const { file } = state;
        // let runtime = "automatic";
        let source = 'react'; // DEFAULT.importSource: "react",
        // const define = (name, id) =>
        // state.set(@babel/plugin-react-jsx/id/jsx, jsxDEV)
        //   set(state, name, createImportLazily(state, path, id, source));

        // define("id/jsx", development ? "jsxDEV" : "jsx");
        // 创建一个懒引入
        const id = 'jsx';
        createImportLazily(state, path, id, source)();
      },
      // jsx元素
      JSXElement(path, file) {
        // let callExpr;
        // if (get(file, "runtime") === "classic") {
        //   // React.createElement
        //   callExpr = buildCreateElementCall(path, file);
        // } else {
        //   // _jsx() 这是一个方法调用 CallExpression
        //   callExpr = buildJSXElementCall(path, file);
        // }
        let callExpr = buildJSXElementCall(path, file);
        // 用新的节点替换当前路径的老节点
        path.replaceWith(t.inherits(callExpr, path.node));
      },
    },
  };
}

function getTag(openingPath) {
  // JSXIdentifier
  // const tagExpr = convertJSXIdentifier(openingPath.node.name, openingPath.node);
  const tagExpr = t.stringLiteral(openingPath.node.name.name);
  let tagName;
  if (t.isIdentifier(tagExpr)) {
    tagName = tagExpr.name;
  } else if (t.isStringLiteral(tagExpr)) {
    tagName = tagExpr.value;
  }

  if (t.react.isCompatTag(tagName)) {
    return t.stringLiteral(tagName);
  } else {
    return tagExpr;
  }
}

/**
 *
 * @param {*} path path是路径 node是里面的节点 节点是可以转换的 type是类型
 * @param {*} file
 * @returns CallExpression 放回一个方法调用
 */
function buildJSXElementCall(path, file) {
  // JSXIdentifier: type
  // children 放在config中
  // JSXAttribute 属性

  // 2. 转换代码 函数的调用
  // _jsx("div", {}, '');
  // _jsx(Literal, ObjectExpression, Literal)

  // JSXOpeningElement get用来获取子路径 path是JSXElement
  const openingPath = path.get('openingElement'); // JSXOpeningElement
  // const tag = getTag(openingPath);

  // (1) type
  const tag = openingPath.node.name; // JSXIdentifier
  const tagName = t.stringLiteral(tag.name); // div
  // console.log(tagName);
  // 参数数组
  const args = [tagName];

  // (2) 属性
  const attribsArray = [];
  const extracted = Object.create(null); // mayBeKey
  // const attributes = openingPath.node.attributes;
  // 遍历属性
  for (const attr of openingPath.get('attributes')) {
    if (attr.isJSXAttribute() && t.isJSXIdentifier(attr.node.name)) {
      // jsx的属性
      const { name } = attr.node.name; // JSXIdentifier
      switch (name) {
        case 'key': {
          // (3) key要单独的处理 可能是表达式
          // const keyValue = convertAttributeValue(attr.node.value);
          const value = attr.node.value; // Literal
          // const keyValue = t.isJSXExpressionContainer(value)
          //   ? value.expression
          //   : value;
          // extracted[name] = keyValue;
          extracted[name] = value;
          break;
        }
        default:
          attribsArray.push(attr); // JSXAttribute
      }
    } else {
      attribsArray.push(attr);
    }
  }
  // console.log(attribsArray, "attribsArray");
  // console.log(extracted, "extracted");
  // (4) children
  // const children = buildChildren(path.node)
  const children = t.react.buildChildren(path.node);
  // console.log(children, "children");
  let attribs;
  // 先新建一个ObjectExpression
  if (attribsArray.length || children.length) {
    // attribsArray的类型是 JSXAttribute
    // 新的是 ObjectExpression
    attribs = buildJSXOpeningElementAttributes(attribsArray, children);
  } else {
    // 不能是null
    attribs = t.objectExpression([]);
  }
  // 参数 arguments
  args.push(attribs);
  // 处理key
  args.push(extracted.key); // StringLiteral 直接复用
  // 要构建一个 call 语句
  // return call(file, children.length > 1 ? "jsxs" : "jsx", args);
  return call(file, '_jsx', args);
}

// 构建一个call语句 CallExpression
function call(pass, name, args) {
  // https://babel.docschina.org/docs/en/6.26.3/babel-types/

  // callee Identifier t.identifier(name) jsx标识符
  const callee = t.identifier(name);
  // t.callExpression(callee, arguments)
  const node = t.callExpression(callee, args);
  return node;
}

// 属性做映射 尽可能的复用
function buildJSXOpeningElementAttributes(attribs, children) {
  const props = attribs.reduce(accumulateAttribute, []);
  if (children?.length > 0) {
    props.push(buildChildrenProperty(children));
  }
  // console.log(props, "props");
  // ObjectExpression 里面多个属性
  return t.objectExpression(props);
}

// 属性 修改type的类型
function accumulateAttribute(array, attribute) {
  const value = convertAttributeValue(attribute.node.value);
  // Literal
  if (t.isStringLiteral(value)) {
    value.value = value.value.replace(/\n\s+/g, ' ');
    delete value.extra?.raw;
  }
  // JSXIdentifier => Identifier
  attribute.node.name = t.stringLiteral(attribute.node.name.name);
  array.push(
    // Property: key: value id=root
    t.inherits(t.objectProperty(attribute.node.name, value), attribute.node),
  );
  return array;
}

// 转换属性
function convertAttributeValue(node) {
  if (t.isJSXExpressionContainer(node)) {
    return node.expression;
  } else {
    return node;
  }
}

function buildChildren(node) {
  const elements = [];
  for (let i = 0; i < node.children.length; i++) {
    let child = node.children[i];
    if (types.isJSXText(child)) {
      elements.push(types.stringLiteral(child.value));
    }
  }
  return elements;
}

// children属性
function buildChildrenProperty(children) {
  let childrenNode;
  if (children.length === 1) {
    childrenNode = children[0];
  } else if (children.length > 1) {
    childrenNode = t.arrayExpression(children);
  } else {
    return undefined;
  }
  // key: Identifier
  // value: childrenNode 复用了
  return t.objectProperty(t.identifier('children'), childrenNode);
}

/**
 *
 * @param {*} pass
 * @param {*} path
 * @param {*} importName
 * @param {*} source
 * @returns
 */
function createImportLazily(pass, path, importName, source) {
  return () => {
    // const actualSource = getSource(source, importName);
    const actualSource = 'react/jsx-runtime';
    // path.node.sourceType === "module"
    // if (isModule(path)) {
    // }
    let reference;
    // let reference = get(pass, `imports/${importName}`);
    // 如果存在就直接return
    // if (reference) return t.cloneNode(reference);
    // 没有就新增导入
    // https://babeljs.io/docs/en/babel-helper-module-imports
    // import {_named as _named} from 'source'
    reference = addNamed(path, importName, actualSource, {
      importedInterop: 'uncompiled',
      importPosition: 'after',
    });
    // set(pass, `imports/${importName}`, reference);
    return reference;
  };
}

// function getSource(source, importName) {
//   return "react/jsx-runtime";
// }

// function addNamed() {}

// 老的转换
function buildCreateElementCall(path, file) {}
